﻿namespace FasterThanLightEngineUnitTests.Math
{
    using System;
    using System.Runtime.Remoting;
    using FasterThanLightEngine.Math;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class Vector2DUnitTest
    {
        [TestMethod]
        public void Vector2D_Accessors_X()
        {
            var vector = new Vector2D(11, 12);

            Assert.AreEqual(11, vector.X);
        }

        [TestMethod]
        public void Vector2D_Accessors_Y()
        {
            var vector = new Vector2D(11, 12);

            Assert.AreEqual(12, vector.Y);
        }

        [TestMethod]
        public void Vector2D_Accessors_Magnitude()
        {
            var vector = new Vector2D(11, 12);
            var expected = Math.Sqrt(11*11 + 12*12);

            Assert.AreEqual(expected, vector.Magnitude);
        }

        [TestMethod]
        public void Vector2D_Accessors_Magnitude2()
        {
            var vector = new Vector2D(11, 12);
            const double expected = 11*11 + 12*12;

            Assert.AreEqual(expected, vector.Magnitude2);
        }

        [TestMethod]
        public void Vector2D_Constructors_Default()
        {
            var vector = new Vector2D();

            Assert.AreEqual(0, vector.X);
            Assert.AreEqual(0, vector.Y);
        }

        [TestMethod]
        public void Vector2D_Constructors_Values()
        {
            var vector = new Vector2D(11, 12);

            Assert.AreEqual(11, vector.X);
            Assert.AreEqual(12, vector.Y);
        }

        [TestMethod]
        public void Vector2D_Contructors_Copy()
        {
            var vector = new Vector2D(11, 12);
            var copiedVector = new Vector2D(vector);

            Assert.AreEqual(11, copiedVector.X);
            Assert.AreEqual(12, copiedVector.Y);
        }

        [TestMethod]
        public void Vector2D_Methods_DotProduct()
        {
            var vectorLeft = new Vector2D(11, 12);
            var vectorRigth = new Vector2D(5, 6);

            var dotProduct = vectorLeft.DotProduct(vectorRigth);
            var expectedDotProduct = vectorLeft.X*vectorRigth.X + vectorLeft.Y*vectorRigth.Y;

            Assert.AreEqual(expectedDotProduct, dotProduct);
        }

        [TestMethod]
        public void Vector2D_Methods_ToVector3D()
        {
            var vector2D = new Vector2D(11, 12);

            var vector3D = vector2D.ToVector3D();

            Assert.AreEqual(11, vector3D.X);
            Assert.AreEqual(12, vector3D.Y);
            Assert.AreEqual(0, vector3D.Z);

            vector3D = vector2D.ToVector3D(Vector2D.VectorPromotionType.XtoXYtoZ);

            Assert.AreEqual(11, vector3D.X);
            Assert.AreEqual(0, vector3D.Y);
            Assert.AreEqual(12, vector3D.Z);
        }

        [TestMethod]
        public void Vector2D_Methods_ToString()
        {
            var vector = new Vector2D(11, 12);

            Assert.AreEqual("(11, 12)", vector.ToString());
        }

        [TestMethod]
        public void Vector2D_Operators_Addition_Vector()
        {
            var vector1 = new Vector2D(11, 12);
            var vector2 = new Vector2D(3, 5);

            var vectorResult = vector1 + vector2;

            Assert.AreEqual(14, vectorResult.X);
            Assert.AreEqual(17, vectorResult.Y);

            vectorResult = vector2 + vector1;

            Assert.AreEqual(14, vectorResult.X);
            Assert.AreEqual(17, vectorResult.Y);
        }

        [TestMethod]
        public void Vector2D_Operators_Subtraction_Vector()
        {
            var vector1 = new Vector2D(11, 12);
            var vector2 = new Vector2D(3, 5);

            var vectorResult = vector1 - vector2;

            Assert.AreEqual(8, vectorResult.X);
            Assert.AreEqual(7, vectorResult.Y);

            vectorResult = vector2 - vector1;

            Assert.AreEqual(-8, vectorResult.X);
            Assert.AreEqual(-7, vectorResult.Y);
        }

        [TestMethod]
        public void Vector2D_Operators_Scaling_Uniform()
        {
            var vector = new Vector2D(11, 12);
            const double scale = 1.5;

            var vectorResult = vector * scale;

            Assert.AreEqual(16.5, vectorResult.X);
            Assert.AreEqual(18, vectorResult.Y);

            vectorResult = scale * vector;

            Assert.AreEqual(16.5, vectorResult.X);
            Assert.AreEqual(18, vectorResult.Y);
        }

        [TestMethod]
        public void Vector2D_Operators_Scaling_NonUniform()
        {
            var vector = new Vector2D(11, 12);
            var vectorScaler = new Vector2D(2, 3);

            var vectorResult = vector*vectorScaler;

            Assert.AreEqual(22, vectorResult.X);
            Assert.AreEqual(36, vectorResult.Y);

            vectorResult = vectorScaler*vector;

            Assert.AreEqual(22, vectorResult.X);
            Assert.AreEqual(36, vectorResult.Y);
        }

        [TestMethod]
        public void Vector2D_Operators_Scaling_InverseUniformScale()
        {
            var vector = new Vector2D(11, 12);
            const double inverseScale = 1.5;

            var vectorResult = vector/inverseScale;

            Assert.AreEqual(7 + (1/3d), vectorResult.X);
            Assert.AreEqual(8, vectorResult.Y);
        }
    }
}
